﻿using System;
using System.Globalization;
using zijian666.Converts.Abstractions;
using zijian666.Converts.Convertor.Base;
using zijian666.Converts.Core;
using zijian666.Converts.Extensions;

namespace zijian666.Converts.Convertor;

/// <summary>
/// <seealso cref="DateTime" /> 转换器
/// </summary>
public class DateTimeOffsetConvertor : FromConvertor<DateTimeOffset>
                               , IFrom<string, DateTimeOffset>
                               , IFrom<DateTime, DateTimeOffset>
                               , IFrom<int, DateTimeOffset>
                               , IFrom<long, DateTimeOffset>
#if NET5_0_OR_GREATER
                               , IFrom<TimeOnly, DateTimeOffset>
                               , IFrom<DateOnly, DateTimeOffset>
#endif
{
    /// <summary>
    /// 日期格式化字符
    /// </summary>
    private static readonly string[] _formats = {
        "HH:mm",
        "HHmmss",
        "HH:mm:ss",
        "yyyyMMdd",
        "yyyy/MM/dd",
        "yyyy-MM-dd",
        "yyyy.MM.dd",
        "yyyyMMddHHmmss",
        "yyyyMMddHHmmssfff",
        "yyyy-MM-dd HH:mm:ss",
        "yyyyMMddHHmmssffffff" ,
        "yyyy-MM-dd HH:mm:ss:fff",
        "yyyy-MM-dd HH:mm:ss.fff",
        "yyyy-MM-dd HH:mm:ss:ffffff" ,
        "yyyy-MM-dd HH:mm:ss.ffffff" , };

    /// <inheritdoc/>
    public ConvertResult<DateTimeOffset> From(IConvertContext context, string input)
    {
        var s = input.Trim();
        if (DateTimeOffset.TryParse(s, out var result))
        {
            return result;
        }
        foreach (var format in _formats)
        {
            if (input.Length == format.Length)
            {
                if (DateTimeOffset.TryParseExact(s, format, null, DateTimeStyles.None, out result))
                {
                    return result;
                }
                break;
            }
            if (input.Length == format.Length + " +08:00".Length)
            {
                if (DateTimeOffset.TryParseExact(s, format + " zzz", null, DateTimeStyles.None, out result))
                {
                    return result;
                }
                break;
            }
        }
        return context.ConvertFail(this, input);
    }

    /// <inheritdoc/>
    public ConvertResult<DateTimeOffset> From(IConvertContext context, DateTime input) => new(input);

    /// <inheritdoc/>
    public ConvertResult<DateTimeOffset> From(IConvertContext context, int input) => UTCHelper.Epoch.AddSeconds(input);

    /// <inheritdoc/>
    public ConvertResult<DateTimeOffset> From(IConvertContext context, long input)
    {
        if (input < 9999999999)
        {
            return UTCHelper.Epoch.AddSeconds(input);
        }
        return UTCHelper.Epoch.AddMilliseconds(input);
    }
#if NET5_0_OR_GREATER
    ConvertResult<DateTimeOffset> IFrom<DateOnly, DateTimeOffset>.From(IConvertContext context, DateOnly input)
        => new(input.ToDateTime(TimeOnly.MinValue));

    ConvertResult<DateTimeOffset> IFrom<TimeOnly, DateTimeOffset>.From(IConvertContext context, TimeOnly input)
        => new(UTCHelper.LocalEpoch.Add(input.ToTimeSpan()));
#endif
}
